package com.myk.game.gobangchess.ai.symmetric;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Queue;

/**
 * 文件名: BlockFinder.java
 * 类名: BlockFinder
 * 功能: 提供对对称棋棋盘进行棋子分块的功能。
 */
public class BlockFinder {

    private static final int BOARD_SIZE = 15;

    /**
     * 对棋盘上的黑白棋子进行分块。
     * 该函数会遍历整个棋盘，使用广度优先搜索 (BFS) 算法找出所有同色相邻棋子构成的棋块。
     *
     * @param board int[][] 类型的二维数组，代表15x15的棋盘。
     *              - 棋盘大小: 15x15。
     *              - 元素值: 1 代表黑棋，-1 代表白棋，0 代表空位。
     * @return Map<Integer, List<List<int[]>>> 类型。
     *         - Key: 棋子颜色 (1 for black, -1 for white)。
     *         - Value: 一个列表，其中每个元素都是一个棋块。
     *         - 每个棋块 (Block) 是一个 List<int[]>，包含了构成该棋块的所有棋子的坐标。
     *         - 每个坐标 (Coordinate) 是一个 int[] 数组，格式为 {row, column}。
     */
    public static Map<Integer, List<List<int[]>>> findBlocks(int[][] board) {
        Map<Integer, List<List<int[]>>> blockMap = new HashMap<>();
        blockMap.put(1, new ArrayList<>());  // 存放黑棋棋块
        blockMap.put(-1, new ArrayList<>()); // 存放白棋棋块

        boolean[][] visited = new boolean[BOARD_SIZE][BOARD_SIZE];

        for (int r = 0; r < BOARD_SIZE; r++) {
            for (int c = 0; c < BOARD_SIZE; c++) {
                // 如果当前位置有棋子且未被访问过
                if (board[r][c] != 0 && !visited[r][c]) {
                    int color = board[r][c];
                    List<int[]> currentBlock = new ArrayList<>();
                    Queue<int[]> queue = new LinkedList<>();

                    queue.add(new int[]{r, c});
                    visited[r][c] = true;

                    // 开始 BFS 搜索，找到所有相连的同色棋子
                    while (!queue.isEmpty()) {
                        int[] currentPos = queue.poll();
                        currentBlock.add(currentPos);

                        // 检查8个相邻方向
                        for (int dr = -1; dr <= 1; dr++) {
                            for (int dc = -1; dc <= 1; dc++) {
                                if (dr == 0 && dc == 0) continue;

                                int nr = currentPos[0] + dr;
                                int nc = currentPos[1] + dc;

                                // 检查边界、是否为同色棋子、是否已访问
                                if (nr >= 0 && nr < BOARD_SIZE && nc >= 0 && nc < BOARD_SIZE &&
                                        !visited[nr][nc] && board[nr][nc] == color) {
                                    visited[nr][nc] = true;
                                    queue.add(new int[]{nr, nc});
                                }
                            }
                        }
                    }
                    // 将找到的完整棋块添加到对应颜色的列表中
                    blockMap.get(color).add(currentBlock);
                }
            }
        }
        return blockMap;
    }

    /**
     * 用于在命令行中打印带索引的棋盘，方便调试和验证。
     * @param board 要打印的棋盘。
     */
    public static void printBoardWithIndices(int[][] board) {
        // 打印列索引
        System.out.print("   ");
        for (int i = 0; i < BOARD_SIZE; i++) {
            System.out.printf("%-3d", i);
        }
        System.out.println("\n-------------------------------------------------");

        // 打印行索引和棋盘内容
        for (int i = 0; i < BOARD_SIZE; i++) {
            System.out.printf("%-2d|", i);
            for (int j = 0; j < BOARD_SIZE; j++) {
                System.out.printf("%-3d", board[i][j]);
            }
            System.out.println();
        }
    }

    /**
     * 主函数，用于调用和验证 findBlocks 函数。
     */
    public static void main(String[] args) {
        // 1. 定义一个15x15的显式棋盘矩阵用于测试
        int[][] testBoard = {
            //0  1  2  3  4  5  6  7  8  9 10 11 12 13 14
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 0
            { 0, 1, 1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1, 0, 0}, // 1
            { 0, 0, 1, 0, 0, 0, 0,-1, 0, 0, 0, 0,-1, 0, 0}, // 2
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 3
            { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 4
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0}, // 5
            { 0, 0, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 0}, // 6
            { 0, 0, 0, 0, 0,-1, 1, 1, 1, 0, 0,-1, 0, 0, 0}, // 7
            { 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0,-1, 0, 0, 0}, // 8
            { 0, 0, 0, 0, 0,-1,-1, 0, 0, 0, 0, 0, 0, 0, 0}, // 9
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 10
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 11
            { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 12
            { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // 13
            { 0, 0, 0, 0, 0, 0, 0, 0,-1, 0, 0, 0, 0, 0, 0}  // 14
        };

        // 2. 打印输入的棋盘状态
        System.out.println("====== 输入的棋盘 ======");
        printBoardWithIndices(testBoard);

        // 3. 调用分块函数
        Map<Integer, List<List<int[]>>> blocks = findBlocks(testBoard);

        // 4. 打印输出结果
        System.out.println("\n====== 棋子分块结果 ======");

        // 打印黑棋棋块
        List<List<int[]>> blackBlocks = blocks.get(1);
        System.out.println("\n黑棋 (1) 棋块数量: " + blackBlocks.size());
        for (int i = 0; i < blackBlocks.size(); i++) {
            System.out.print("  黑棋块 " + (i + 1) + ": ");
            for (int[] pos : blackBlocks.get(i)) {
                System.out.print(Arrays.toString(pos) + " ");
            }
            System.out.println();
        }

        // 打印白棋棋块
        List<List<int[]>> whiteBlocks = blocks.get(-1);
        System.out.println("\n白棋 (-1) 棋块数量: " + whiteBlocks.size());
        for (int i = 0; i < whiteBlocks.size(); i++) {
            System.out.print("  白棋块 " + (i + 1) + ": ");
            for (int[] pos : whiteBlocks.get(i)) {
                System.out.print(Arrays.toString(pos) + " ");
            }
            System.out.println();
        }
    }
}